#include "BoundingBox.h"

template<class T>
void Swap(T &a,T &b)
{
	T t = a;
	a = b;
	b = t;
}
template<class T>
T Min(const T &a, const T &b)
{
	return a < b ? a : b;
}
template<class T>
T Max(const T &a, const T &b)
{
	return a > b ? a : b;
}

BoundingBox::BoundingBox()
{
}


BoundingBox::BoundingBox(Vector3 _min, Vector3 _max):min(_min),max(_max)
{
}

BoundingBox::~BoundingBox()
{
}

bool BoundingBox::Hit(lzw::Ray ray)
{
	Vector3 a = Vector3(1, 1, 1) / ray.direction;
	Vector3 tMin = (min - ray.begin) / ray.direction;
	Vector3 tMax = (max - ray.begin) / ray.direction;
	if (a.GetX() < 0)
	{
		Swap(tMin.data[0], tMax.data[0]);
	}
	if (a.GetY() < 0)
	{
		Swap(tMin.data[1], tMax.data[1]);
	}
	if (a.GetZ() < 0)
	{
		Swap(tMin.data[2], tMax.data[2]);
	}

	if (tMin.GetX() > tMax.GetY() || tMin.GetX() > tMax.GetZ() || tMin.GetY() > tMax.GetX() || tMin.GetY() > tMax.GetZ() || tMin.GetZ() > tMax.GetX() || tMin.GetZ() > tMax.GetY())
	{
		return false;
	}

	return true;
}

bool BoundingBox::Hit(lzw::Ray ray, float & t)
{
	Vector3 a = Vector3(1, 1, 1) / ray.direction;
	Vector3 tMin = (min - ray.begin) / ray.direction;
	Vector3 tMax = (max - ray.begin) / ray.direction;
	if (a.GetX() < 0)
	{
		Swap(tMin.data[0], tMax.data[0]);
	}
	if (a.GetY() < 0)
	{
		Swap(tMin.data[1], tMax.data[1]);
	}
	if (a.GetZ() < 0)
	{
		Swap(tMin.data[2], tMax.data[2]);
	}

	if (tMin.GetX() > tMax.GetY() || tMin.GetX() > tMax.GetZ() || tMin.GetY() > tMax.GetX() || tMin.GetY() > tMax.GetZ() || tMin.GetZ() > tMax.GetX() || tMin.GetZ() > tMax.GetY())
	{
		return false;
	}
	int i;
	t = tMin.MaxValue(i);
	return true;
}

BoundingBox BoundingBox::Combine(BoundingBox b1, BoundingBox b2)
{
	Vector3 min,max;
	for (int i = 0; i < 3; i++)
	{
		if (b1.min.data[i] < b2.min.data[i])
		{
			min.data[i] = b1.min.data[i];
		}
		else
		{
			min.data[i] = b2.min.data[i];
		}

		if (b1.max.data[i] > b2.max.data[i])
		{
			max.data[i] = b1.max.data[i];
		}
		else
		{
			max.data[i] = b2.max.data[i];
		}
	}
	return BoundingBox(min, max);
}

BoundingBox BoundingBox::Combine(BoundingBox box)
{
	*this = Combine(*this, box);
	return *this;
}

Vector3 BoundingBox::GetCenter()
{
	return (min + max) / 2;
}
